
from OpenGL.GL import *

from amt.cg.core.object3d import Object3D

class Object3DList(list):
    '''
    This class defines a list containing only Object3D instances.
    It provides methods that operates all objects inside it.
    '''

    def __init__(self, *items):
        '''
        Constructor.
        Inserts items into this object list.
        '''
        self._check_type(*items)
        list.__init__(self, items)
        
    def draw_all(self, mode=GL_RENDER):
        '''
        Draws all 3D objects in this list.
        mode - defines in which mode the objects will be drawn,
        GL_RENDER or GL_SELECT
        '''
        for i in range(len(self)):
            obj = self[i]
            obj.draw(mode, name=i)

    def get_bounding_box(self):
        '''
        Returns the planes that define a bounding box for the
        3D objects. 
        '''
        box = [self[0].center_position[0] - 1.0,
               self[0].center_position[0] + 1.0,
               self[0].center_position[1] - 1.0,
               self[0].center_position[1] + 1.0,
               self[0].center_position[2] - 1.0,
               self[0].center_position[2] + 1.0]

        for obj in self:
            size = obj.arcball_radius
            for i in range(3):  # x, y, z
                if obj.center_position[i] - size < box[i*2]:      # minimum
                    box[i*2] = obj.center_position[i] - size
                elif obj.center_position[i] + size > box[i*2+1]:  # maximum
                    box[i*2+1] = obj.center_position[i] + size
        
        return box
    
    def _check_type(self, *items):
        '''
        Checks if the items that will be inserted into this list are 
        Object3D instances.
        Should be called in all insertion methods.
        '''
        for item in items:
            if not isinstance(item, Object3D):
                raise TypeError("Only Object3D instances can be inserted.")

    # Overrides list's insertion methods, checking if the inserted item
    # is an Object3D.
    def __setitem__(self, i, y):
        self._check_type(y)
        list.__setitem__(self, i, y)
    
    def append(self, obj):
        self._check_type(obj)
        list.append(self, obj)
    
    def insert(self, index, obj):
        self._check_type(obj)
        list.insert(self, index, obj)

